.unwrap()
은 Result값을 match
하여 Error일 때 알아서 panic!
매크로를 실행해주는 단축어다.
이전의 코드를 이렇게 한줄로 줄일 수 있다.
let f = BufReader::new(File::open(&args.path).unwrap());
에러 자체를 return하게 하고 싶을 때는 ?
을 이용할 수 있다.
이 경우 main
함수의 리턴값이 바뀌므로 함수의 시그니처를 변경해줘야한다
fn main() -> Result<(), Box<dyn std::error::Error>> {
//
//... 코드 중간에 Error가 반환될 수 있다.
//
Ok(()) // 여전히 종료는 Unit type을 반환한다
}
Box<dyn std::error::Error
는 모든 에러를 담을 수 있는 타입이다.
#[derive(Debug)]
struct CustomError(String);
fn main() -> Result<(), CustomError> {
let content = std::fs::read_to_string(path)
.map_err(|err| CustomError(format!("Error reading `{}`: {}", path, err)))?;
println!("file content: {}", content);
Ok(())
}
output:
Error: CustomError("Error reading `test.txt`: No such file or directory (os error 2)")
이런 형태의 에러처리는 자주 쓰인다. 다만 에러 자체를 저장하기보다 CustomError
안의 문자열만 알게 되는 문제가 있다.
이때는 anyhow 라는 라이브러리를 사용한다. Context
trait을 활용하여 에러에 대한 추가 메세지를 작성해주면서 원래의 에러까지 유지할 수 있다.
장점은? 에러에 대한 체이닝이 가능해진다.
use anyhow::{Context, Result};
fn main() -> Result<()> {
let path = "test.txt";
let content = std::fs::read_to_string(path)
.with_context(|| format!("could not read file `{}`", path))?;
println!("file content: {}", content);
Ok(())
}
output:
Error: could not read file `test.txt`
Caused by:
No such file or directory (os error 2)